/*
* Copyright (c)  2017, ueboot.com
* All rights reserved.
* 2017-11-05 18:13:23
*/
package com.ueboot.weishop.service.goods.impl;

import com.ueboot.core.exception.BusinessException;
import com.ueboot.weishop.entity.goods.GoodsInfoEntity;
import com.ueboot.weishop.entity.goods.GoodsSalesSpecEntity;
import com.ueboot.core.repository.BaseRepository;
import com.ueboot.weishop.repository.goods.GoodsSalesSpecRepository;
import com.ueboot.core.service.impl.BaseServiceImpl;
import com.ueboot.weishop.service.goods.GoodsSalesSpecService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVRecord;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Example;
import org.springframework.data.domain.ExampleMatcher;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionCallback;
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
import org.springframework.transaction.support.TransactionTemplate;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.PersistenceContext;
import java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * Created by yangkui  on 2017-11-05 18:13:23.
 *
 * @author yangkui
 * @since 2.0 by autocode
 */
@Slf4j
@Service
public class GoodsSalesSpecServiceImpl extends BaseServiceImpl<GoodsSalesSpecEntity> implements GoodsSalesSpecService {
    @Autowired
    private GoodsSalesSpecRepository goodsSalesSpecRepository;

    @Autowired
    private EntityManagerFactory emf;

    @Autowired
    private PlatformTransactionManager platformTransactionManager;

    @Override
    protected BaseRepository getBaseRepository() {
        return goodsSalesSpecRepository;
    }

    @Override
    public List<GoodsSalesSpecEntity> findSpec(String specValueFullPathValue) {
        return goodsSalesSpecRepository.findBySpecValueFullPathValue(specValueFullPathValue);
    }

    /**
     * 根据商品ID查询销售规格
     *
     * @param pageable
     * @param goodsInfoId
     * @return
     */
    @Override
    public Page<GoodsSalesSpecEntity> findByGoodsInfoId(Pageable pageable, Long goodsInfoId) {
        GoodsSalesSpecEntity spec = new GoodsSalesSpecEntity();
        GoodsInfoEntity g = new GoodsInfoEntity();
        g.setId(goodsInfoId);
        spec.setGoodsInfo(g);
        ExampleMatcher matcher = ExampleMatcher.matching().withIgnoreNullValues()
                .withMatcher("goodsInfo.id", matcher1 -> matcher1.exact());
        return goodsSalesSpecRepository.findAll(Example.of(spec, matcher), pageable);
    }

    @Override
    public List<GoodsSalesSpecEntity> findSpecAndName(String specValueFullPathValue, String name) {
        return goodsSalesSpecRepository.findBySpecValueFullPathValueAndName(specValueFullPathValue, name);
    }


    /**
     * 根据商品ID，删除所有商品的价格数据
     *
     * @param goodsInfoId 商品ID
     */
    @Override
    @Transactional(rollbackFor = Exception.class, timeout = 120, propagation = Propagation.REQUIRED)
    public void deleteGoodsSalesSpecEntitiesByGoodsInfoId(Long goodsInfoId) {
        goodsSalesSpecRepository.deleteGoodsSalesSpecEntitiesByGoodsInfoId(goodsInfoId);
    }

    @Override
    public List<GoodsSalesSpecEntity> findSpecAndGoodsId(String specValueFullPathValue, Long goodsInfoId) {
        return goodsSalesSpecRepository.findBySpecValueFullPathValueAndGoodsInfoId(specValueFullPathValue, goodsInfoId);
    }

    @Override
    public GoodsSalesSpecEntity findById(Long id) {
        return goodsSalesSpecRepository.findById(id);
    }

    /**
     * 导入文件
     *
     * @param goodsInfoId
     * @param in
     */
    @Override
    public void importSalesSpec(Long goodsInfoId, InputStream in) {
        try {
            log.info("开始保存价格列表数据");
            log.info("删除原有数据");
            EntityManager entityManager = emf.createEntityManager();
            EntityTransaction transaction = entityManager.getTransaction();

            TransactionTemplate transactionTemplate = new TransactionTemplate(platformTransactionManager);
            transactionTemplate.execute(new TransactionCallbackWithoutResult() {
                @Override
                protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) {
                    transaction.begin();
                    Integer count = entityManager.createQuery("delete com.ueboot.weishop.entity.goods.GoodsSalesSpecEntity s where s.goodsInfo.id = " + goodsInfoId).executeUpdate();
                    log.info("删除了{}条", count);
                    transaction.commit();
                }
            });
            log.info("开始执行批量保存操作");
            BufferedReader br = new BufferedReader(new InputStreamReader(in, "GBK"));
            Iterable<CSVRecord> records = CSVFormat.RFC4180.parse(br);
            Integer i = 0;
            GoodsInfoEntity g = new GoodsInfoEntity();
            g.setId(goodsInfoId);
            List<GoodsSalesSpecEntity> list = new ArrayList<>();
            ExecutorService cachedThreadPool = Executors.newFixedThreadPool(50);
            for (CSVRecord record : records) {
                if (i == 0) {
                    i++;
                    continue;
                }
                String c0 = record.get(0);
                String c1 = record.get(1);
                String c2 = record.get(2);
                String c3 = record.get(3);
                String c4 = record.get(4);
                String c5 = record.get(5);
                String c6 = record.get(6);
                String c7 = record.get(7);
                String c8 = record.get(8);
                String c9 = record.get(9);
                String c10 = record.get(10);
                String c11 = record.get(11);
                String c12 = record.get(12);
                String c13 = record.get(13);
                String c14 = record.get(14);
                String c15 = null;
                if (record.size() > 15) {
                    c15 = record.get(15);
                }
                GoodsSalesSpecEntity spec = new GoodsSalesSpecEntity();
                spec.setExt1(c6);
                spec.setExt2(c3);
                spec.setExt3(c0 + c1 + c2);
                spec.setName(c10);
                if (StringUtils.isNotEmpty(c14)) {
                    spec.setOriginPrice(Integer.valueOf(c14.trim()) * 100);
                }
                spec.setPrice(Integer.valueOf(c13.trim()) * 100);
                spec.setSn(c11);
                spec.setSpecValueFullPathName(c6 + "/" + c8);
                spec.setSpecValueFullPathValue(c3 + "/" + c7);
                spec.setStock(StringUtils.isNotEmpty(c15) ? Integer.valueOf(c15) : 1000000);
                spec.setGoodsInfo(g);
                list.add(spec);
                if (i % 100 == 0) {
                    MyThread t = new MyThread(emf, list);
                    cachedThreadPool.execute(t);
                    list = new ArrayList<>();
                }
                i++;

            }
            if (!list.isEmpty()) {
                transaction.begin();
                for (GoodsSalesSpecEntity spec : list) {
                    entityManager.persist(spec);
                }
                entityManager.flush();
                entityManager.clear();
                transaction.commit();
                log.info("###原线程保存数据库成功，结束！！共:{}条", list.size());
            }


        } catch (IOException e) {
            log.error("价格导入失败！", e);
            throw new BusinessException("数据导入失败！");
        }

    }


}

class MyThread implements Runnable {

    private EntityManagerFactory emf;
    private Logger logger = LoggerFactory.getLogger(MyThread.class);

    List<GoodsSalesSpecEntity> list;

    public MyThread(EntityManagerFactory emf, List<GoodsSalesSpecEntity> list) {
        this.emf = emf;
        this.list = list;
    }

    @Override
    public void run() {
        logger.info("启动新的线程，开始保存数据库");
        EntityManager entityManager = emf.createEntityManager();
        EntityTransaction transaction = entityManager.getTransaction();
        transaction.begin();
        for (GoodsSalesSpecEntity spec : list) {
            entityManager.persist(spec);
        }
        entityManager.flush();
        entityManager.clear();
        transaction.commit();
        logger.info("新的线程保存数据库成功，共:{}条", list.size());

    }
}
